(function() {
  function Radix() {
    var radix = function(key, val, t) {
      key = '' + key;
      if (!t && u !== val) {
        radix.last = key < radix.last ? radix.last : key;
        radix.sort = null;
      }
      t = t || radix[_] || (radix[_] = {});
      var i = 0,
        l = key.length - 1,
        k = key[i],
        at,
        tmp;
      while (!(at = t[k]) && i < l) {
        k += key[++i];
      }
      if (!at) {
        if (
          !map(t, function(r, s) {
            var ii = 0,
              kk = '';
            while (s[ii] == key[ii]) {
              kk += s[ii++];
            }
            if (kk) {
              if (u === val) {
                if (ii <= l) {
                  return;
                }
                return ((tmp || (tmp = {}))[s.slice(ii)] = r);
              }
              var __ = {};
              __[s.slice(ii)] = r;
              (__[key.slice(ii)] = {})[$] = val;
              (t[kk] = {})[_] = __;
              delete t[s];
              return true;
            }
          })
        ) {
          if (u === val) {
            return;
          }
          (t[k] || (t[k] = {}))[$] = val;
        }
        if (u === val) {
          return tmp;
        }
      } else if (i == l) {
        if (u === val) {
          return u === (tmp = at[$]) ? at[_] : tmp;
        }
        at[$] = val;
      } else {
        if (u !== val) {
          at.sort = null;
        }
        return radix(key.slice(++i), val, at[_] || (at[_] = {}));
      }
    };
    return radix;
  }

  Radix.map = function map(radix, cb, opt, pre) {
    pre = pre || [];
    var t = radix[_] || radix,
      keys = radix.sort || (radix.sort = Object.keys(t).sort()),
      i = 0,
      l = keys.length;
    for (; i < l; i++) {
      var key = keys[i],
        tree = t[key],
        tmp;
      if (u !== (tmp = tree[$])) {
        tmp = cb(tmp, pre.join('') + key, key, pre);
        if (u !== tmp) {
          return tmp;
        }
      } else if (opt) {
        cb(u, pre.join(''), key, pre);
      }
      if ((tmp = tree[_])) {
        pre.push(key);
        tmp = map(tree, cb, opt, pre);
        //tmp = map(tmp, cb, opt, pre);
        if (u !== tmp) {
          return tmp;
        }
        pre.pop();
      }
    }
  };

  Object.keys =
    Object.keys ||
    function(o) {
      return map(o, function(v, k, t) {
        t(k);
      });
    };

  if (typeof window !== 'undefined') {
    var Gun = window.Gun;
    window.Radix = Radix;
  } else {
    var Gun = require('../gun');
    try {
      module.exports = Radix;
    } catch (e) {}
  }

  var map = Gun.obj.map,
    no = {},
    u;
  var $ = String.fromCharCode(30),
    _ = String.fromCharCode(29);
})();
